﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Runtime.Remoting.Metadata.W3cXsd2001;
using System.Windows.Forms;
using Communergy.Common;
using Communergy.Common.Events;
using CommunergyUploader;
using CurrentCostLibrary;

namespace CurrentCostGUI
{


    public partial class Meter : Form, IMeterView
    {
		#region Fields (9) 

        //List<HistoricalEnergyReading> hourlyEnergyReadingsForUpload = new List<HistoricalEnergyReading>();
        List<HistoricalEnergyReading> dailyEnergyReadings = new List<HistoricalEnergyReading>();
        IEnergyMonitorProvider device;
        //List<RealtimeEnergyReading> realtimeEnergyReadingsForUpload = new List<RealtimeEnergyReading>();
        List<HistoricalEnergyReading> hourlyEnergyReadings = new List<HistoricalEnergyReading>();
        DateTime lastUploadDateTime = DateTime.Now;
        List<LogEntry> log = new List<LogEntry>();
        //List<HistoricalEnergyReading> dailyEnergyReadingsForUpload = new List<HistoricalEnergyReading>();
        List<HistoricalEnergyReading> monthlyEnergyReadings = new List<HistoricalEnergyReading>();
// = new CurrentCostDevice();
        List<RealtimeEnergyReading> realtimeEnergyReadings = new List<RealtimeEnergyReading>();
        Communergy.Common.Meter thisMeter = null;
        //List<HistoricalEnergyReading> monthlyEnergyReadingsForUpload = new List<HistoricalEnergyReading>();
        TimeSpan uploadInterval;

		#endregion Fields 

		#region Constructors (1) 

        public Meter()
        {
            InitializeComponent();
        }

		#endregion Constructors 

		#region Delegates and Events (1) 

		// Delegates (1) 

        //to pass messages from Device reading thread back to UI thread
        delegate void StringParameterDelegate(string value);

		#endregion Delegates and Events 

		#region Methods (13) 

		// Public Methods (3) 

        public void BindMeterToForm(Communergy.Common.Meter selectedMeter)
        {
            thisMeter = selectedMeter;
            this.Text = thisMeter.MeterName;
            var registered = thisMeter.MeterGuid != null;
            chkUploadHistorical.Enabled = registered;
            chkUploadLive.Enabled = registered;
            btnRegisterMeter.Visible = !registered;
            txtMeterId.Visible = registered;
            if (registered)
            {
                txtMeterId.Text = selectedMeter.MeterGuid.ToString();
            }
        }

        //TODO - put  Updating functionality back in
        public void RunUpdater()
        {

            ////todo -move to Presenter?

            //do
            //{
            //    string remoteMeterId = thisMeter.MeterGuid;
            //    string localMeterId = thisMeter.MeterId.ToString();

            //    if (chkUploadLive.Checked)
            //    {

            //        IRealtimeRepository currentCostUpload = CommunergyClientFactory.GetUploadRealtimeTarget();

            //        var lastRealTime = currentCostUpload.GetLastElectricityRealtime(remoteMeterId);

            //        lastUploadDateTime = lastRealTime != null ? lastRealTime.ReadingDateTime : lastUploadDateTime;

            //        var localCache = CommunergyClientFactory.GetLocalRealtimeCache();
            //        var realtimeEnergyReadingsForUpload = localCache.Get_ElectricityRealtime(localMeterId, lastUploadDateTime, DateTime.Now);

            //        if (realtimeEnergyReadingsForUpload != null && realtimeEnergyReadingsForUpload.Count > 0)
            //        {
            //            try
            //            {
            //                UpdateStatus(string.Format("Sending {0} live records to Communergy", realtimeEnergyReadingsForUpload.Count));
            //                currentCostUpload.Insert_ElectricityRealtime(remoteMeterId, realtimeEnergyReadingsForUpload);
            //                UpdateStatus(string.Format("Sent {0} live records to Communergy", realtimeEnergyReadingsForUpload.Count));
            //                lastUploadDateTime = DateTime.Now;
            //            }
            //            catch (Exception excep)
            //            {
            //                UpdateStatus(excep.Message);
            //            }
            //        }
            //    }

            //    if (chkUploadHistorical.Checked)
            //    {
            //        //TODO - Factory
            //        IHistoricRepository currentCostUploadHistory = new UploadWeatherWCFAndCommunergy();
            //        if (hourlyEnergyReadingsForUpload.Count > 0)
            //        {
            //            lock (hourlyEnergyReadingsForUpload)
            //            {
            //                try
            //                {
            //                    UpdateStatus(string.Format("Sending {0} hourly records to Communergy", hourlyEnergyReadingsForUpload.Count));
            //                    currentCostUploadHistory.Insert_ElectricityHourly(remoteMeterId, hourlyEnergyReadingsForUpload);
            //                    UpdateStatus(string.Format("Sent {0} hourly records to Communergy", hourlyEnergyReadingsForUpload.Count));
            //                    hourlyEnergyReadingsForUpload = new List<HistoricalEnergyReading>();
            //                }
            //                catch (Exception excep)
            //                {
            //                    UpdateStatus(excep.Message);
            //                }
            //            }
            //        }

            //        if (dailyEnergyReadingsForUpload.Count > 0)
            //        {
            //            lock (dailyEnergyReadingsForUpload)
            //            {
            //                try
            //                {
            //                    UpdateStatus(string.Format("Sending {0} daily records to Communergy", dailyEnergyReadingsForUpload.Count));
            //                    currentCostUploadHistory.Insert_ElectricityDaily(remoteMeterId, dailyEnergyReadingsForUpload);
            //                    UpdateStatus(string.Format("Sent {0} daily records to Communergy", dailyEnergyReadingsForUpload.Count));
            //                    dailyEnergyReadingsForUpload = new List<HistoricalEnergyReading>();
            //                }
            //                catch (Exception excep)
            //                {
            //                    UpdateStatus(excep.Message);
            //                }
            //            }

            //        }

            //        if (monthlyEnergyReadingsForUpload.Count > 0)
            //        {
            //            lock (monthlyEnergyReadingsForUpload)
            //            {
            //                try
            //                {
            //                    UpdateStatus(string.Format("Sending {0} monthly records to Communergy", monthlyEnergyReadingsForUpload.Count));
            //                    currentCostUploadHistory.Insert_ElectricityMonthly(remoteMeterId, monthlyEnergyReadingsForUpload);
            //                    UpdateStatus(string.Format("Sent {0} monthly records to Communergy", monthlyEnergyReadingsForUpload.Count));
            //                    monthlyEnergyReadingsForUpload = new List<HistoricalEnergyReading>();
            //                }
            //                catch (Exception excep)
            //                {
            //                    UpdateStatus(excep.Message);
            //                }
            //            }
            //        }
            //    }

            //    Thread.Sleep((int)uploadInterval.TotalMilliseconds);
            //} while (true);
        }

        public void UpdateStatus(string value)
        {
            if (InvokeRequired)
            {
                // We're not in the UI thread, so we need to call BeginInvoke
                BeginInvoke(new StringParameterDelegate(UpdateStatus), new object[] { value });
                return;
            }
            // Must be on the UI thread if we've got this far
            lblMeterInfo.Text = value;
            log.Add(new LogEntry { LogDateTime = DateTime.Now, Entry = value });

            var displayData = (from l in log
                               orderby l.LogDateTime descending
                               select string.Format("{0}: {1}", l.LogDateTime.ToString(), l.Entry)).Take(100).ToList(); ;
            lstLog.DataSource = displayData;

        
        }
		// Private Methods (10) 

        private void btnGetSingleDay_Click(object sender, EventArgs e)
        {
            var dateStart = dateChooseSingleDay.Value.Date;
            var dateEnd = dateStart.AddDays(1).AddSeconds(-1);
            var meterId = thisMeter.MeterId.ToString();

            var xAxis = chartSingleDay.ChartAreas[0].AxisX;
            xAxis.Minimum = dateStart.ToOADate();
            xAxis.Maximum = dateEnd.ToOADate();
            xAxis.LabelStyle.Format = "T";

            var ReportQueryEventArgs = new ReportQueryEventArgs
            {
                ReportQueryParameters = new ReportQueryParameters
                {
                    MeterId = meterId,
                    StartDateTime = dateStart,
                    EndDateTime  = dateEnd
                }
            };
            //raises GetSingleDay event, bound
            if (this.GetSingleDayReport != null)
            {
                this.GetSingleDayReport(this, ReportQueryEventArgs);
            }
        }

        private void btnRegisterMeter_Click(object sender, EventArgs e)
        {
            string message = string.Format("Meter '{0}' is not registered on the Communergy Database. Register now?", thisMeter.MeterName);
            var result = MessageBox.Show(message, "Register new Meter", MessageBoxButtons.OKCancel);
            if (result == DialogResult.OK)
            {
                this.RegisterMeterOnline(this, null);
                //TODO - seperate thread
                var remoteMeterRepository = CommunergyClientFactory.GetRemoteMeterStore();
                //TODO -- userId
                thisMeter.UserId = GuiConfig.GetUserGuid();
                var originalId = this.thisMeter.MeterId;
                var savedMeter = remoteMeterRepository.CreateNewMeter(thisMeter);
                BindMeterToForm(savedMeter);
                savedMeter.MeterId = originalId;
                var localRepository = CommunergyClientFactory.GetLocalMeterStore();
                localRepository.SaveMeterDetails(savedMeter);
            }
        }

        void device_EnergyReading(object sender, EnergyReadingEventArgs re)
        {
        }

        private void DisconnectMeter()
        {
            this.StopMonitoring(this, null);

            //if (device != null)
            //{
                
            //    device.EndReadings();
            //    device = null;
            //}
            //UpdateStatus("No meter connected");
        }

        private void InitialiseAndStartMonitoring()
        {
            if (InitialiseDevice != null)
            {
                var energyMonitorProviderEventArgs = new EnergyMonitorProviderEventArgs
                {
                    EnergyMonitorProvider = device,
                    MeterId = thisMeter.MeterId.ToString()
                };
                this.InitialiseDevice(this, energyMonitorProviderEventArgs);
                UpdateStatus("Waiting for meter");

            }
            if (StartMonitoring != null)
            {
                this.StartMonitoring(this, null);
            }
        }

        private void Meter_Load(object sender, EventArgs e)
        {
            SetupSerialPortDropDown();
            string uploadIntervalConfig = ConfigurationSettings.AppSettings["uploadInterval"];
            uploadInterval = SoapDuration.Parse(uploadIntervalConfig);
        }

        private void rdoCurrentCost_CheckedChanged(object sender, EventArgs e)
        {
            SetDevice();
        }

        private void rdoMonitor_CheckedChanged(object sender, EventArgs e)
        {
            SetDevice();
        }

        private void SetDevice()
        {

            if (rdoMonitor.Checked)
            {
                if (rdoCurrentCost.Checked)
                {
                    var port = cboSerialPort.SelectedItem.ToString();
                    device = CurrentCostMonitorFactory.GetCurrentCostMonitor(port);
                }
                else if (rdoRandom.Checked)
                {
                    device = CurrentCostMonitorFactory.GetRandomDataGenerator();
                }
                if (rdoMonitor.Checked && device != null)
                {
                    //TODO raise event InitialiseDevice
                    InitialiseAndStartMonitoring();
                }
                else
                {
                    
                }
            }
            else
            {
                DisconnectMeter();
            }
        }

        private void SetupSerialPortDropDown()
        {
            cboSerialPort.Items.Clear();
            for (int i = 1; i < 10; i++)
            {
                var thisComPort = string.Format("COM{0}", i);
                cboSerialPort.Items.Add(thisComPort);
            }
            var configComPort = ConfigurationSettings.AppSettings["port"];
            cboSerialPort.SelectedItem = configComPort;

        }

		#endregion Methods 



        #region Bind charts

        public void BindLiveData()
        {
            var dataToBind = realtimeEnergyReadings.OrderByDescending(re => re.ReadingDateTime).ToList();
            dgRealtime.DataSource = dataToBind;
            liveChart.DataSource = realtimeEnergyReadings;
            liveChart.DataBind();
        }

        public void BindHourlyData()
        {
            dgHourly.DataSource = hourlyEnergyReadings.OrderByDescending(h => h.ReadingDateTime).ToList();
            hourlyChart.DataSource = hourlyEnergyReadings;
            hourlyChart.DataBind();

        }
        public void BindDailyData()
        {
            dgDaily.DataSource = dailyEnergyReadings.OrderByDescending(d => d.ReadingDateTime).ToList();
            dailyChart.DataSource = dailyEnergyReadings;
            dailyChart.DataBind();
        }
        public void BindMonthlyData()
        {
            dgMonthly.DataSource = monthlyEnergyReadings;
            monthlyChart.DataSource = monthlyEnergyReadings;
            monthlyChart.DataBind();

        }

        public void BindSingleDayReport(Report dailyData)
        {
            var realtimeData = dailyData.RealtimeEnergyReadings["RealtimeData"];
            var hourly = dailyData.HistoricalEnergyReadings["Hourly"];

            var realtimeSeries = chartSingleDay.Series["Realtime"];
            foreach (var datapoint in realtimeData)
            {
                int newIndex = realtimeSeries.Points.AddXY(datapoint.ReadingDateTime.ToOADate(), (double)datapoint.Watts);
            }
            var hourlySeries = chartSingleDay.Series["Hourly"];
            foreach (var datapoint in hourly)
            {
                int newIndex = hourlySeries.Points.AddXY(datapoint.ReadingDateTime.ToOADate(), (double)datapoint.KWh);
                hourlySeries.Points[newIndex].ToolTip = string.Format("{0:HH:mm}-{1:HH:mm} - {2} kWh", datapoint.ReadingDateTime, datapoint.ReadingDateTime.AddHours(1).AddMinutes(-1), datapoint.KWh);
            }
        }


        #endregion

        #region IMeterView Members

        public event EventHandler<EnergyMonitorProviderEventArgs> InitialiseDevice;

        public event EventHandler<EventArgs> RegisterMeterOnline;

        public event EventHandler<ReportQueryEventArgs> GetSingleDayReport;

        public event EventHandler<EventArgs> StartMonitoring;

        public event EventHandler<EventArgs> StopMonitoring;

        public event EventHandler<EventArgs> StartUpload;

        public List<HistoricalEnergyReading> HourlyEnergyReadings
        {
            set
            {
                hourlyEnergyReadings = value;
                MethodInvoker updateHistoricalData = new MethodInvoker(BindHourlyData);
                Invoke(updateHistoricalData);
            }
        }

        public List<HistoricalEnergyReading> DailyEnergyReadings
        {
            set
            {
                dailyEnergyReadings = value;
                MethodInvoker updateHistoricalData = new MethodInvoker(BindDailyData);
                Invoke(updateHistoricalData);
            }
        }

        public List<HistoricalEnergyReading> MonthlyEnergyReadings
        {
            set
            {
                monthlyEnergyReadings = value;
                MethodInvoker updateHistoricalData = new MethodInvoker(BindMonthlyData);
                Invoke(updateHistoricalData);
            }
        }

       


        public List<RealtimeEnergyReading> RealtimeEnergyReadings
        {
            set
            {
                realtimeEnergyReadings = value;
                MethodInvoker updateHistoricalData = new MethodInvoker(BindLiveData);
                Invoke(updateHistoricalData);
            }
        }

        public event EventHandler<EventArgs> StopUpload;

        #endregion

        #region IMeterView Members


        List<EnergyData> IMeterView.HourlyEnergyReadings
        {
            set { throw new NotImplementedException(); }
        }

        List<EnergyData> IMeterView.DailyEnergyReadings
        {
            set { throw new NotImplementedException(); }
        }

        List<EnergyData> IMeterView.MonthlyEnergyReadings
        {
            set { throw new NotImplementedException(); }
        }

        List<EnergyData> IMeterView.RealtimeEnergyReadings
        {
            set { throw new NotImplementedException(); }
        }

        #endregion
    }



    public struct LogEntry
    {
		#region Data Members (2) 

        public string Entry { get; set; }

        public DateTime LogDateTime { get; set; }

		#endregion Data Members 
    }
}
